-- cmd_login_cc
-- Create by panyl
-- 玩家登录aaa服务器请求验证

-- 内部函数声明
local onAuthOk
local onAuthFail;
local onConnected;
local onConnectFail;

function Operation.cmd_login_cc(account, password, ip, port, version, extraPara, extraParaRaw)
    if true ~= AccountM.checkAccount(account) then
        -- 没有通过验证
        return
    end

    -- 设置登录状态，一个可唯一识别区分的id就行，用来查看登录到哪个阶段
    LoginM.set_login_stage(LOGIN_STATUS_CC_1);

    -- 去掉账号头尾空格
    account = AccountM.removeSpace(account);

    if not isIpv4(ip) then
        -- 如果dilist中配置了候选cc_ip列表
        if _G["dislist"] and _G["dislist"]["cc_ip_list"] and #_G["dislist"]["cc_ip_list"] > 0 then
            -- 尝试解析域名
            local ipRet = socket.dns.toip(ip);
            if ipRet == nil then
                -- 解析失败，随机一个CC的IP
                ip = table.randomValue(_G["dislist"]["cc_ip_list"]);

                -- 设置登录状态，一个可唯一识别区分的id就行，用来查看登录到哪个阶段
                LoginM.set_login_stage(LOGIN_STATUS_CC_2);

                -- 设置标记，后面连接aaa和gs时也直接使用ip
                _G["use_pure_ip"] = true;
                cclog("cc_ip:" .. ip);
                if DOWNLOAD_ERROR_REPORT_URL then
                    local msg = string.format("[%s] try use cc ip %s to connect.", account, ip);
                    postDataToRemoteHost(DOWNLOAD_ERROR_REPORT_URL, msg);
                end
            end
        end
    end

    trace("cmd_login_cc", "帐号(%s)登录aaa服务器 ip：(%s) port (%d) ", account, ip, port);

    -- 当前是连接状态
    if Socket.isConnected() or Socket.isConnecting() then
        -- TODO: 需要返回错误码
        cclog("正在连接服务器，请稍候！")
        return
    end

    cclog("正在连接服务器...")

    -- 记录下客户端的平台
    extraPara["client_os"] = getPlatformName();

    -- 记录信息
    _G.aaaAccountInfo = {
        ["account"]  = account,
        ["password"] = password,
        ["version"]  = version,
        ["extra_para"] = extraPara,
        ["extra_para_raw"] = extraParaRaw,
    }

    _G.ip = ip;
    _G.port = port;

    -- 移除事件的关注
    EventMgr.remove("cmd_login_cc", event.NETWORK_CONNECTED)
    EventMgr.remove("cmd_login_cc", event.NETWORK_DISCONNECTED)

    -- 关注事件
    EventMgr.register("cmd_login_cc", event.NETWORK_CONNECTED, onConnected);
    EventMgr.register("cmd_login_cc", event.NETWORK_DISCONNECTED, onConnectFail);

    -- 连接服务器
    Socket.connect(ip, port);

    -- 处理完成
    return true;
end

-- 限制新玩家登录提示语
local function showNewUserLoginForbiddenMsg()
    local forbiddenConfig = _G["dislist"]["new_user_forbidden_cfg"];

    -- 禁止新玩家进行登陆
    local function okFunc()
        if forbiddenConfig then
            local url = forbiddenConfig["btn_url"] or "";
            if sizeof(url) > 0 then
                openUrl(url);
            end
        end
    end

    local defaultText = nil;
    local btnText = defaultText;
    local deafaultStr = "Error: New user is forbidden.";
    local str = deafaultStr;
    if forbiddenConfig then
        str = forbiddenConfig["content_"..getLang()];
        if getLang() == "zh" then
            str = forbiddenConfig["content_zh"] or deafaultStr;
            btnText = forbiddenConfig["btn_text_zh"] or defaultText;
        elseif getLang() == "tw" then
            str = forbiddenConfig["content_tw"] or forbiddenConfig["content_zh"] or deafaultStr;
            btnText = forbiddenConfig["btn_text_tw"] or forbiddenConfig["btn_text_zh"] or defaultText;
        else
            str = forbiddenConfig["content_en"] or deafaultStr;
            btnText = forbiddenConfig["btn_text_en"] or defaultText;
        end
    end

    confirm2(CONFIRM_TYPE_OK, getLocStr("game_board"), str, okFunc, nil, btnText, nil);
    return;
end

function getContactStr()
    local contactStr = "";
    if _G["dislist"] and _G["dislist"]["contact_info"] then
        local arr = string.explode(_G["dislist"]["contact_info"], "|");
        if #arr > 1 then
            local lang = getLang();
            if lang == "zh" then
                contactStr = arr[1];
            elseif lang == "tw" then
                contactStr = arr[2] or "";
            else
                contactStr = arr[3] or "";
            end
        end
    end
    return contactStr;
end

-- 连接服务器成功后的处理
onConnected = function()
    -- 移除事件的关注
    EventMgr.remove("cmd_login_cc", event.NETWORK_CONNECTED)
    EventMgr.remove("cmd_login_cc", event.NETWORK_DISCONNECTED)

    LoginM.set_login_stage(LOGIN_STATUS_CC_3);

    if _G["use_pure_ip"] == true then
        if DOWNLOAD_ERROR_REPORT_URL then
            local msg = string.format("[%s] ip %s connect succeed.", tostring(_G.aaaAccountInfo.account), _G.ip);
            postDataToRemoteHost(DOWNLOAD_ERROR_REPORT_URL, msg);
        end
    end

    local v = _G.aaaAccountInfo

    local platform = TEST_PLATFORM or v["extra_para"]["3rdplatform"];

    local macAddress = NetworkStatus.getMacAddress();

    -- 发送获取登录区组配置的消息
    Operation.cmd_get_login_dist(v.account, {
         ["platform"] = platform,   -- 渠道信息
         ["country_code"] = cc.Device:getCountryCode(),   -- 国家代码
         ["mac_address"] = macAddress,  -- mac地址
         ["use_pure_ip"] = _G["use_pure_ip"],
         });

    cclog("发送获取登录区组配置的消息完毕，等待返回消息到达。\n");

    -- 等待消息到达
    MSG.waitMessageArrival("MSG_GET_LOGIN_DIST3", function(para)
        local ip        = para.ip;
        local port      = para.port;
        local version   = para.version;
        local maintainInfo = para.maintain_info;
        local status    = maintainInfo.status;
        local leftTime = maintainInfo.left_time or 0;

        LoginM.set_login_stage(LOGIN_STATUS_CC_4);

        -- 区组维护提示语
        local function showMaintainMsg()
            local contactStr = getContactStr();
            local tipInfo = MaintenanceM.getTips(status) or {};

            local title = tipInfo["title"] or getLocStr("world_tree_maintenance");
            local desc = tipInfo["desc"] or getDialogStr("dialog_238");
            desc = string.gsub(desc, "{contact}", contactStr);

            local extra = tipInfo["extra"] or "";

            if string.len(extra) > 0 then
                desc = desc .. "\n" .. extra;
            end

            local function okFunc()
                -- 退出游戏
                exitSystem();
            end

            confirm2(CONFIRM_TYPE_OK, title, desc, okFunc, nil,
                nil, nil, { ["backFunc"] = okFunc,
                ["leftTimeDesc"] = {"maintain", desc, leftTime}});
        end

        -- 限制老玩家登录提示语
        local function showLoginForbiddenMsg()
            local function okFunc()
                -- 退出游戏
                exitSystem();
            end

            local deafaultStr = getDialogStr("dialog_238");
            local str = _G["dislist"]["login_forbidden_msg"] or deafaultStr;
            if getLang() ~= "zh" and getLang() ~= "tw" then
                str = deafaultStr;
            end

            confirm2(CONFIRM_TYPE_OK, getLocStr("game_board"), str, okFunc, nil,
                nil, nil, { ["backFunc"] = okFunc });
        end

        if status ~= "success" then
            -- 登录失败

            -- 关闭通信中界面
            closeCommunicatingForm();
            -- 断开连接
            Socket.disconnect();

            -- 根据 status 弹出提示框
            if status == "login_forbidden" then
                -- 该渠道禁止老玩家登录
                showLoginForbiddenMsg();
            elseif status == "new_user_limit" then
                -- 该渠道禁止新玩家登录
                showNewUserLoginForbiddenMsg();
            else
                -- 区组在维护
                showMaintainMsg();
            end
            return;
        end

        -- 后续流程
        local function callback()
            -- 先断开链接
            Socket.disconnect();

            -- 如果有原始的认证信息，需要丢到aaa重新认证
            local aaaExtra = v.extra_para_raw or v.extra_para;

            _G["aaa_ip"] = ip;
            _G["aaa_port"] = port;

            Operation.cmd_login_aaa(v.account, v.password, ip, port, v.version, aaaExtra);
        end

        -- 检查是否需要重新下载资源
        LoginM.checkResDownload(version, callback);
    end, 15);
end

-- 连接失败的处理
onConnectFail = function()
    trace("cmd_login_cc", "登录失败了");

    -- 移除事件的关注
    EventMgr.remove("cmd_login_cc", event.NETWORK_CONNECTED)
    EventMgr.remove("cmd_login_cc", event.NETWORK_DISCONNECTED)
end
